#include "mgr/HttpMgr.h"
#include "mgr/WorkerMgr.h"
#include "tool/Utility.h"
#include "hv/hbase.h"
#include "hv/requests.h"
#include "mgr/LogMgr.h"
#include <iostream>
#include <sys/time.h>

int HttpMgr::Init(const std::string& conf_file) {
	Json::Value root;
	if (!Utility::LoadJson(conf_file, root)) return -1;
	int port = root["port"].asInt();
	// std::string admin_url = root["admin_url"].asString();
	const Json::Value& adminurls = root["admin_url"];
	for (unsigned int i = 0; i < adminurls.size(); i++)
	{
		std::string url = adminurls[i].asString();
		AdminSiteInfo asi;
		asi.url = url;
		this->admin_sites[url] = asi;
		if (i == 0){
			this->main_admin_url = url;
		}
	}
	
	//// �ܺ� ���� ţ�ư�
	HV_MEMCHECK;

	this->router.GET("/heartbeat", [](HttpRequest* req, HttpResponse* resp)
	{
		// TODO 心跳 暂不知道要回个啥 就200结束
		return 200;
	});

	// curl -v http://ip:port/upload
	this->router.GET("/upload", [this](HttpRequest* req, HttpResponse* resp)
	{
		// 用来上传 算法完成的图片上传到后台
		// 发送 到workermgr线程中进行处理
		LOG_INFO("upload msg receive: " << hv::dump_query_params(req->query_params))
		HttpMsg msg(HttpMsgType_TaskUpload, hv::dump_query_params(req->query_params));	
		WorkerMgr::instance().Push(msg);
	
		return 200;
	});

	this->server.service = &router;
	this->server.port = port;

	// this->admin_url = admin_url;
	// 直接去请求 管理页面 的摄像头 信息 + 任务信息
	// TODO 如果不考虑时序的话 应该就是这样子了
	// this->ReqDeviceList();
	// this->ReqRealTaskList();

	return 0;
}

void HttpMgr::Run() {
	// uncomment to test multi-processes
	// server.setProcessNum(4);
	// uncomment to test multi-threads
	// server.setThreadNum(4);
	this->server.start();
}

// 封装 Get接口
HttpRet HttpMgr::hvGet(const std::string &adminurl, const std::string &opt, http_headers &headers){
	HttpRet ret;
	auto resp = requests::get((adminurl + opt).c_str(), headers);
	if (resp == NULL){
		LOG_ERROR(adminurl << opt << " request get fail ")
	}
	else{
		// printf("%d %s\r\n", resp->status_code, resp->status_message());
		// printf("%s\n", resp->body.c_str());
		Json::Reader reader;
		ret.ret = reader.parse(resp->body, ret.output);
	}
	return ret;
}

// 封装 Post接口
HttpRet HttpMgr::hvPost(const std::string &adminurl, const std::string &opt, const std::string &json, http_headers &headers){
	HttpRet ret;
	auto resp = requests::post((adminurl + opt).c_str(), json, headers);
	if (resp == NULL){
		LOG_ERROR(adminurl << opt << " request post fail ")
	}
	else{
		// printf("%d %s\r\n", resp->status_code, resp->status_message());
		// printf("%s\n", resp->body.c_str());
		Json::Reader reader;
		ret.ret = reader.parse(resp->body, ret.output);
	}
	return ret;
}

// 封装 upload接口
HttpRet HttpMgr::hvUpload(const std::string &adminurl, const std::string &opt, const std::string& name, const std::string &file, http_headers &headers){
	HttpRet ret;
	// TODO type不知道有没有用处 暂时先写死了这个参数
	std::map<std::string, std::string> params;
	params["name"] = name;
	params["size"] = "";
	params["type"] = "image/jpg";
	// LOG_INFO(adminurl << opt << "|" << name << "|" << file << " request upload ")
	auto resp = requests::uploadFormFile((adminurl + opt).c_str(), "file", file.c_str(), params, HTTP_POST, headers);
	
	if (resp == NULL){
		LOG_ERROR(adminurl << opt << " request upload fail ")
	}
	else{
		// 这个返回值真棒 
		Json::Reader reader;
		ret.ret = reader.parse(resp->body, ret.output);
		LOG_INFO(adminurl << "||" << ret.output.toStyledString())
	}
	return ret;
}

bool HttpMgr::hvPipeLine(const HttpPipeLines& pipelines, std::map<std::string, HttpRet>& outputs, bool multi){
	if (this->admin_sites.size() < 0){
		LOG_ERROR("No Admin Site Configs")
		return false;
	}
	
	std::map<std::string, AdminSiteInfo> _targets;
	if (multi){
		_targets = this->admin_sites;
	}else{
		_targets[this->main_admin_url] = this->admin_sites[this->main_admin_url];
	}
	
	for (auto& it: _targets){
		AdminSiteInfo& info = it.second;
		HttpRet ret;
		HttpParams param;
		param.url = info.url;
		int _lap = 2;	
		for (auto pipe = pipelines.begin(); pipe != pipelines.end();){
			// 每次都需要重新设置TOKEN 不然毫无卵用
			param.headers["token"] =  this->admin_sites[it.first].token;
			ret = (*pipe)(ret, param);
			if (!ret.ret){
				LOG_ERROR(info.url << " ret is false failure")
				break;
			}
			// 重试次数到了 直接炸
			if (_lap <= 0){
				LOG_ERROR(info.url << " lap <= 0 failure")
				break;
			}
			// 说明token过期 需要重连
			if (ret.output["code"].asInt() == -2){
				// 进行重连  并重新尝试执行当前pipe 执行次数只为1次!
				this->ReqLogin();
				_lap--;
				continue;
			}
			// 结果非0 直接炸
			if (ret.output["code"].asInt() != 0){
				ret.ret = false;
				// 打个LOG算了 printf看不到
				LOG_ERROR(ret.ret << "||" << ret.output.toStyledString())
				break;
			}
			pipe++;
		}
		outputs[info.url] = ret;
	}
	// 只返回主要的内容是否执行成功了
	return outputs[main_admin_url].ret;
}

// 用户登录 /user/login
bool HttpMgr::ReqLogin(){
	HttpPipeLines pipelines;
	pipelines.push_back([this](const HttpRet& _r, HttpParams& _p){
		Json::Value jroot_req;
		jroot_req["username"] = "AiServer";
		jroot_req["password"] = "aifgd68hrt/fgd6";
		std::string opt = "/user/login";
		_p.headers["Content-Type"] = "application/json";
		return this->hvPost(_p.url, opt, jroot_req.toStyledString(), _p.headers);
	});
	LOG_INFO("ReqLogin =====================================================")
	std::map<std::string, HttpRet> outputs;
	bool r = this->hvPipeLine(pipelines, outputs, true);
	for (auto& it:outputs){
		LOG_INFO("ReqLogin result =====================================================" << it.second.output.toStyledString())
		if (!it.second.ret){
			continue;
		}
		this->admin_sites[it.first].token = it.second.output["data"]["token"].asString();
	}
	
	return r;
}

// 请求设备列表 /device/list
bool HttpMgr::ReqDeviceList(Json::Value& root){
	HttpPipeLines pipelines;
	pipelines.push_back([this](const HttpRet& _r,  HttpParams& _p){
		std::string opt = "/device/all";
		return this->hvGet(_p.url, opt, _p.headers);
	});
	std::map<std::string, HttpRet> outputs;
	if (this->hvPipeLine(pipelines, outputs)){
		root = outputs[main_admin_url].output;
		return true;
	}
	return false;
}

// 请求任务列表 /realtask/list
bool HttpMgr::ReqRealTaskList(Json::Value& root){
	HttpPipeLines pipelines;
	pipelines.push_back([this](const HttpRet& _r,  HttpParams& _p){
		std::string opt = "/realtask/list?pagesize=10000";
		return this->hvGet(_p.url, opt, _p.headers);
	});
	std::map<std::string, HttpRet> outputs;
	if (this->hvPipeLine(pipelines, outputs)){
		root = outputs[main_admin_url].output;
		return true;
	}
	return false;
}

// 城管技战列表接口 /skill/list
bool HttpMgr::ReqSkillList(Json::Value &root){
	HttpPipeLines pipelines;
	pipelines.push_back([this](const HttpRet& _r,  HttpParams& _p){
		Json::Value jroot_req;
		jroot_req["iStart"] = 1;
		jroot_req["pagesize"] = 10000;
		std::string opt = "/skill/list";
		_p.headers["Content-Type"] = "application/json";
		return this->hvPost(_p.url, opt, jroot_req.toStyledString(),  _p.headers);
	});
	std::map<std::string, HttpRet> outputs;
	if (this->hvPipeLine(pipelines, outputs)){
		root = outputs[main_admin_url].output;
		return true;
	}
	return false;
}

// 任务记录 /img/add root_upload["data"]["path"].asString();
bool HttpMgr::PostUploadTask(int iTaskType, const std::string& location, const std::string& name, const std::string& pic, int iTaskId, const std::string& taskName, const std::string& createTime){
	HttpPipeLines pipelines;
	pipelines.push_back([this, &name, &pic](const HttpRet& _r,  HttpParams& _p){
		// 1 上传图片
		std::string opt = "/uploadfile";
		return this->hvUpload(_p.url, opt, name, pic, _p.headers);
	});
	pipelines.push_back([this, &iTaskType, &location, &iTaskId, &taskName, &createTime](const HttpRet& _r,  HttpParams& _p){
		// 2 上传任务
		std::string thumburl = _r.output["data"]["path"].asString();
		
		Json::Value jroot_req;
		jroot_req["sceneId"] = iTaskType;
		jroot_req["location"] = location;
		jroot_req["thumb"] = thumburl;
		jroot_req["taskId"] = iTaskId;
		jroot_req["taskName"] = taskName;
		jroot_req["createTime"] = createTime;
		std::string opt = "/img/add";
		_p.headers["Content-Type"] = "application/json";
		return this->hvPost(_p.url, opt, jroot_req.toStyledString(),  _p.headers);
	});
	std::map<std::string, HttpRet> outputs;
	return this->hvPipeLine(pipelines, outputs, true);
}

// 技战记录 /alarm/add
bool HttpMgr::PostUploadAlarm(int iSkill, const std::string &sRule, const std::string &sSustainTime, const std::string& name, const std::string& pic, const std::string &createTime){
	HttpPipeLines pipelines;
	pipelines.push_back([this, &name, &pic](const HttpRet& _r,  HttpParams& _p){
		// 1 上传图片
		std::string opt = "/uploadfile";
		return this->hvUpload(_p.url, opt, name, pic, _p.headers);
	});
	pipelines.push_back([this, &iSkill, &sRule, &sSustainTime, &createTime](const HttpRet& _r,  HttpParams& _p){
		// 2 上传任务
		std::string thumburl = _r.output["data"]["path"].asString();
		
		Json::Value jroot_req;
		jroot_req["iSkill"] = iSkill;
		jroot_req["sRule"] = sRule;
		jroot_req["sSustainTime"] = sSustainTime;
		jroot_req["thumb"] = thumburl;
		jroot_req["createTime"] = createTime;
		std::string opt = "/alarm/add";
		_p.headers["Content-Type"] = "application/json";
		return this->hvPost(_p.url, opt, jroot_req.toStyledString(),  _p.headers);
	});
	std::map<std::string, HttpRet> outputs;
	return this->hvPipeLine(pipelines, outputs, true);
}

